package ch.gibb.javamvc;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.awt.*;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 * User: Bernard
 * Date: 27.02.13
 * Time: 07:00
 * To change this template use File | Settings | File Templates.
 */
public class WebPageMapper extends HttpServlet {
    private static final String VIEWS_PATH = "/LearnIT/LearnIT-1.0/views";
    private static final String WEB_MAPP_PATH = "/LearnIT/LearnIT-1.0/web-app.xml";

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(System.getProperty("user.dir"));
        String url = getURL(request);
        String site = null;
        String params = null;
        String demeter = String.valueOf('?');
        if (url.contains(demeter)) {
            site = url.split(demeter)[0];
            params = url.split(demeter)[1];
        } else
            site = url;
        try {
            System.out.println("Site is " + site);
            WebPageBean page = getWebPageBeanFromURL(site);
            if (page == null)
                //Todo: write code for 404
                return;
            ActionInterface action = page.getAction();
            action.openPage();
            VelocityEngine ve = getVelocityEngine();
            VelocityContext context = new VelocityContext();
            for (PropertyDescriptor pd : Introspector.getBeanInfo(action.getClass()).getPropertyDescriptors()) {
                if (pd.getReadMethod() != null && !"class".equals(pd.getName())){
                    System.out.println("Method: " + pd.getName());
                    context.put(pd.getName(), pd.getReadMethod().invoke(action));
                    System.out.println("Method added: " + pd.getName());
                }
            }
            Template t = ve.getTemplate(page.getViewPath());
            StringWriter writer = new StringWriter();
            t.merge(context, writer);
            response.getWriter().write(writer.toString());
        } catch (Exception e) {
            //Todo: Write handling
            System.err.println("Failed parsing because " + e.getMessage());
            e.printStackTrace();
        }
    }

    private String getURL(HttpServletRequest request) {
        StringBuffer url = request.getRequestURL();
        if (request.getQueryString() != null) {
            url.append('?');
            url.append(request.getQueryString());
        }
        String[] urlParts = url.toString().split("/JavaMVC-1.0/");
        return (urlParts.length > 1) ? urlParts[1] : "";
    }

    private WebPageBean getWebPageBeanFromURL(String URL) throws Exception {
        WebPageBean temp = new WebPageBean();
        temp.setUrl(URL);
        List<WebPageBean> pages = getAllPages();
        if (!pages.contains(temp))
            return null;
        return pages.get(pages.indexOf(temp));
    }

    private List<WebPageBean> getAllPages() throws Exception {
        InputStream is = this.getClass().getResourceAsStream(WEB_MAPP_PATH);
        if (null == is)
            throw new Exception();
        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
        Document doc = docBuilder.parse(is);
        //Document doc = docBuilder.parse(new File(WEB_MAPP_PATH));
        List<WebPageBean> webPages = new ArrayList<WebPageBean>();
        doc.getDocumentElement().normalize();
        NodeList pages = doc.getElementsByTagName("page");
        for (int i = 0; i < pages.getLength(); i++) {
            try {
                WebPageBean page = new WebPageBean();
                Element element = (Element) pages.item(i);
                page.setId(element.getAttribute("id"));
                page.setUrl(element.getAttribute("url"));
                Class actionClass = Class.forName(element.getElementsByTagName("controller").item(0).getTextContent());
                page.setAction((ActionInterface) actionClass.newInstance());
                page.setViewPath(element.getElementsByTagName("view").item(0).getTextContent());
                webPages.add(page);
            } catch (Exception e) {
                //Todo: Log event
            }
        }
        return webPages;
    }

    private VelocityEngine getVelocityEngine(){
        Properties prop = new Properties();
        String absolutePath = new File(Thread.currentThread().getContextClassLoader().getResource("").getFile()).getParentFile().getParentFile().getPath();
        prop.put("file.resource.loader.path", absolutePath + VIEWS_PATH);
        System.out.println("absolute path is : " + absolutePath);
        System.out.println("keyset is : " + prop.keySet());
        Enumeration em = prop.keys();
        while (em.hasMoreElements()) {
            String str = (String) em.nextElement();
            System.out.println(str + ": " + prop.get(str));
        }
        VelocityEngine ve = new VelocityEngine();
        ve.init(prop);
        return ve;
    }
}
